//============================================================================
//                                  I B E X
// File        : ibex_OptimizerConfig.h
// Author      : Gilles Chabert
// Copyright   : IMT Atlantique (France)
// License     : See the LICENSE file
// Created     : Dec 11, 2014
// Last Update : Oct 13, 2019
//============================================================================

#ifndef __IBEX_OPTIMIZER_CONFIG_H__
#define __IBEX_OPTIMIZER_CONFIG_H__

#include "ibex_Ctc.h"
#include "ibex_Bsc.h"
#include "ibex_LoupFinder.h"
#include "ibex_CellBufferOptim.h"

namespace ibex {

class Optimizer;

/**
 * \ingroup optim
 *
 * \brief Optimizer Configuration.
 *
 * This class allows to set all the parameters of the optimizer.
 *
 * This is an abstract class. In itself, it contains getters and setters for
 * the basic parameters (like the precision, the timeout, etc.). The definition
 * of complex parameters like the contractor, bisector, etc. may vary from one
 * strategy to another and is the purpose of subclasses.
 * See in particular DefaultOptimizerConfig, which implements the default setting
 * for ibexopt.
 *
 */
class OptimizerConfig {
public:

	/**
	 * \brief Create new optimizer configuration.
	 *
	 * All the fields are set to their default values
	 * (see static constants below).
	 */
	OptimizerConfig();

	/**
	 * \brief Delete this.
	 */
	virtual ~OptimizerConfig() { }

	/**
	 * \brief Set relative precision on the objective.
	 */
	void set_rel_eps_f(double rel_eps_f);

	/**
	 * \brief Set absolute precision on the objective.
	 */
	void set_abs_eps_f(double abs_eps_f);

	/**
	 * \brief Set variable precision.
	 *
	 * Was used in older versions of ibexopt for bisection control.
	 *
	 * \deprecated. Should be 0.
	 */
	void set_eps_x(double eps_x);

	/**
	 * \brief Set trace activation flag.
	 *
	 * The value can be fixed by the user.
	 * - 0 (by default): nothing is printed
	 * - 1:              prints every loup/uplo update.
	 * - 2:              prints also each handled node (warning: can generate very
	 *                   long trace).
	 */
	void set_trace(int trace);

	/**
	 * \brief Set time limit.
	 *
	 * Maximum CPU time used by the strategy.
	 * This parameter allows to bound time consumption.
	 * The value can be fixed by the user.
	 */
	void set_timeout(double timeout);

	/**
	 * \brief Set whether the output has to be in the extended space.
	 *
	 * If true, the COV structure generated by the optimizer will
	 * be in the extended space (variables+objective values).
	 * If false, the structure will be in the original space (variables
	 * only).
	 */
	void set_extended_cov(bool extended_cov);

	/**
	 * \brief Set whether anticipated upper bounding has to be applied.
	 *
	 * If true, the search space is not only contracted w.r.t.
	 *         f(x) <= loup
	 * but
	 *         f(x) <= loup - eps
	 * where eps is the required precision on the objective
	 * (the cumul of absolute and relative precision).
	 *
	 * Default value: true.
	 */
	void set_anticipated_upper_bounding(bool antipated_upper_bounding);

	/** see #set_rel_eps_f(). */
	double get_rel_eps_f() const;

	/** see #set_abs_eps_f(). */
	double get_abs_eps_f() const;

	/** see #set_eps_x(). */
	double get_eps_x() const;

	/** see #set_trace(). */
	int get_trace() const;

	/** see #set_timeout(). */
	double get_timeout() const;

	/** see #set_extended_cov(). */
	bool with_extended_cov() const;

	/** see #set_anticipated_upper_bounding(). */
	bool with_anticipated_upper_bounding() const;

	/** Default goal relative precision: 1e-3. */
	static constexpr double default_rel_eps_f = 1e-03;

	/** Default goal absolute precision: 1e-7. */
	static constexpr double default_abs_eps_f = 1e-07;

	/** Default bisection precision: 0. */
	static constexpr double default_eps_x = 0;

	/** Default trace mode: 0 (none). */
	static constexpr int default_trace = 0;

	/** Default timeout: -1 (none). */
	static constexpr int default_timeout = -1;

	/** Default COV output mode: extended (enabled). */
	static constexpr bool default_extended_cov = true;

	/** Default anticipated upper bounding : true (enabled). */
	static constexpr bool default_anticipated_UB = true;

protected:

	friend class Optimizer;

	// ============================================================================
	// the following getters must be called only once the configuration
	// is over (all basic CONFIGeters are set) => reserved for Optimizer.
	// ============================================================================
	virtual unsigned int nb_var()=0;

	virtual Ctc& get_ctc()=0;

	virtual Bsc& get_bsc()=0;

	virtual LoupFinder& get_loup_finder()=0;

	virtual CellBufferOptim& get_cell_buffer()=0;

	virtual int goal_var()=0;
	// ============================================================================

	double rel_eps_f;
	double abs_eps_f;
	double eps_x;
	int trace;
	double timeout;
	bool extended_COV;
	bool anticipated_UB;
};

inline OptimizerConfig::OptimizerConfig() {
	rel_eps_f      = OptimizerConfig::default_rel_eps_f;
	abs_eps_f      = OptimizerConfig::default_abs_eps_f;
	eps_x          = OptimizerConfig::default_eps_x;
	trace          = OptimizerConfig::default_trace;
	timeout        = OptimizerConfig::default_timeout;
	extended_COV   = OptimizerConfig::default_extended_cov;
	anticipated_UB = OptimizerConfig::default_anticipated_UB;
}

inline void OptimizerConfig::set_rel_eps_f(double _rel_eps_f)     { rel_eps_f = _rel_eps_f; }

inline void OptimizerConfig::set_abs_eps_f(double _abs_eps_f)     { abs_eps_f = _abs_eps_f; }

inline void OptimizerConfig::set_eps_x(double _eps_x)             { eps_x = _eps_x; }

inline void OptimizerConfig::set_trace(int _trace)                { trace = _trace; }

inline void OptimizerConfig::set_timeout(double _timeout)         { timeout = _timeout; }

inline void OptimizerConfig::set_extended_cov(bool _extended_COV) { extended_COV = _extended_COV; }

inline void OptimizerConfig::set_anticipated_upper_bounding(bool _antipated_UB) { anticipated_UB = _antipated_UB; }

inline double OptimizerConfig::get_rel_eps_f() const                 { return rel_eps_f; }

inline double OptimizerConfig::get_abs_eps_f() const                 { return abs_eps_f; }

inline double OptimizerConfig::get_eps_x() const                     { return eps_x; }

inline int OptimizerConfig::get_trace() const                        { return trace; }

inline double OptimizerConfig::get_timeout() const                   { return timeout; }

inline bool OptimizerConfig::with_extended_cov()  const              { return extended_COV; }

inline bool OptimizerConfig::with_anticipated_upper_bounding() const { return anticipated_UB; }

} /* namespace ibex */

#endif /* __IBEX_OPTIMIZER_CONFIG_H__ */
